package utils

import (
	"sync"
	"time"
)

const sessionTime = 300                 //每5分钟检测一遍过期session
var SessionMagage = NewSessionMgr(7200) //无操作session两小时过期

/*Session会话管理*/
type SessionMgr struct {
	mLock        sync.RWMutex        //互斥(保证线程安全)
	mMaxLifeTime int64               //session有效时间
	mSessions    map[string]*Session //保存session的指针[sessionID] = session
}

// 创建会话管理器(maxLifeTime:最长生命周期)
func NewSessionMgr(lifeTime int64) *SessionMgr {
	mgr := &SessionMgr{mMaxLifeTime: lifeTime, mSessions: make(map[string]*Session)}
	//session过期机制
	go mgr.GC()
	return mgr
}

// 在开始页面登陆页面，开始Session
func (mgr *SessionMgr) SessionStart(sessionID string) string {
	mgr.mLock.Lock()
	defer mgr.mLock.Unlock()
	if sessionID == "" {
		sessionID = RandomString(32)
		var session = &Session{mSessionID: sessionID, mLastTimeAccessed: time.Now(), mValues: make(map[interface{}]interface{})}
		mgr.mSessions[sessionID] = session
	}

	return sessionID
}

// 结束session
func (mgr *SessionMgr) SessionEnd(sessionID string) {
	mgr.mLock.Lock()
	defer mgr.mLock.Unlock()
	delete(mgr.mSessions, sessionID)
}

// 设置session里面的值
func (mgr *SessionMgr) SetSessionVal(sessionID string, key interface{}, value interface{}) {
	mgr.mLock.Lock()
	defer mgr.mLock.Unlock()

	if session, ok := mgr.mSessions[sessionID]; ok {
		session.mValues[key] = value
	}
}

// 得到session里面的值
func (mgr *SessionMgr) GetSessionVal(sessionID string, key interface{}) interface{} {
	mgr.mLock.RLock()
	defer mgr.mLock.RUnlock()

	if session, ok := mgr.mSessions[sessionID]; ok {
		if val, ok := session.mValues[key]; ok {
			return val
		}
	}

	return nil
}

// 得到sessionID列表
func (mgr *SessionMgr) GetSessionIDList() []string {
	mgr.mLock.RLock()
	defer mgr.mLock.RUnlock()

	sessionIDList := make([]string, 0)
	for k := range mgr.mSessions {
		sessionIDList = append(sessionIDList, k)
	}

	return sessionIDList[0:]
}

func (mgr *SessionMgr) CheckSession(sessionID string) string {
	mgr.mLock.Lock()
	defer mgr.mLock.Unlock()

	if session, ok := mgr.mSessions[sessionID]; ok {
		session.mLastTimeAccessed = time.Now() //判断合法性的同时，更新最后的访问时间
		return sessionID
	}

	return ""
}

// 更新最后访问时间
func (mgr *SessionMgr) SetLastAccessTime(sessionID string) {
	mgr.mLock.RLock()
	defer mgr.mLock.RUnlock()

	if session, ok := mgr.mSessions[sessionID]; ok {
		session.mLastTimeAccessed = time.Now()
	}
}

// GC回收
func (mgr *SessionMgr) GC() {
	mgr.mLock.Lock()
	defer mgr.mLock.Unlock()

	for sessionID, session := range mgr.mSessions {
		//删除超过时限的session
		if session.mLastTimeAccessed.Unix()+mgr.mMaxLifeTime < time.Now().Unix() {
			delete(mgr.mSessions, sessionID)
		}
	}

	//定时回收
	time.AfterFunc(time.Duration(sessionTime)*time.Second, func() { mgr.GC() })
}

/*会话*/
type Session struct {
	mSessionID        string                      //唯一id
	mLastTimeAccessed time.Time                   //最后访问时间
	mValues           map[interface{}]interface{} //其它对应值(保存用户所对应的一些值，比如用户权限之类)
}
